﻿#include "netif.h"
#include "mblock.h"
#include "sys_plat.h"
#include "exmsg.h"
#include "ether.h"
#include "protocol.h"
#include "routetbl.h"

static netif_t netif_buffer[NETIF_DEV_CNT];
static mblock_t netif_mblock;
static nlist_t netif_list;
static netif_t *netif_default; // 默认网络接口,只用于往外发,所以不能作为环回网络接口

#if DBG_DISP_ENABLED(DBG_NETIF_LEVEL)
void display_netif_list()
{
    plat_printf("netif list:\n");
    nlist_node_t *p;
    nlist_for_each(p, &netif_list)
    {
        netif_t *netif = nlist_entry(netif_t, node, p);
        plat_printf("name: %s ", netif->name);

        switch (netif->state)
        {
        case NETIF_CLOSED:
            plat_printf("state: %s ", "closed");
            break;
        case NETIF_OPENED:
            plat_printf("state: %s ", "opened");
            break;
        case NETIF_ACTIVE:
            plat_printf("state: %s ", "active");
            break;
        default:
            plat_printf("state: %s ", "error");
        }

        switch (netif->type)
        {
        case NETIF_TYPE_ETHER:
            printf("type: %s ", "ether");
            break;
        case NETIF_TYPE_LOOP:
            printf("type: %s ", "loop");
            break;
        case NETIF_TYPE_NONE:
            printf("type: %s ", "none");
            break;
        default:
            plat_printf("type: %s ", "error");
        }

        plat_printf("mtu: %d\n", netif->mtu);

        dbg_dump_ipaddr("ipaddr: ", &netif->ipaddr);
        dbg_dump_ipaddr("netmask: ", &netif->netmask);
        dbg_dump_ipaddr("gateway: ", &netif->gateway);
        dbg_dump_hwaddr("hwaddr: ", netif->hwaddr.addr, netif->hwaddr.len);
    }
}
#else
void display_netif_list() {}
#endif

static link_layer_t *link_layers[NETIF_TYPE_SIZE];

/**
 * @brief 获取对应协议的链路层回调函数
 */
static const link_layer_t *netif_get_layer(netif_type_t type)
{
    if (type <= NETIF_TYPE_NONE || type >= NETIF_TYPE_SIZE)
    {
        return NULL;
    }
    return link_layers[type];
}

/**
 * @brief 初始化网络接口管理相关
 */
net_err_t netif_init()
{
    DBG_INFO(DBG_NETIF_LEVEL, "netif init begin!");

    nlist_init(&netif_list);
    mblock_init(&netif_mblock, netif_buffer, sizeof(netif_t), NETIF_DEV_CNT, NLOCKER_NONE);
    plat_memset(link_layers, 0, sizeof(link_layers));
    netif_default = NULL;

    DBG_INFO(DBG_NETIF_LEVEL, "netif init end");

    return NET_ERR_OK;
}

/**
 * @brief 打开网络接口
 * @param name 网络接口名称
 * @param ops 网络接口硬件层面操作函数入口
 * @param ops_data 用于网络接口硬件层面操作
 */
netif_t *netif_open(const char *name, const netif_ops_t *ops, void *ops_data)
{
    // 先申请存放网络接口的空间
    netif_t *netif = mblock_alloc(&netif_mblock, DELIVER_NO_WAITTIME);
    if (!netif)
    {
        DBG_ERROR(DBG_NETIF_LEVEL, "alloc netif failed!");
        return NULL;
    }

    ipaddr_set_any(&netif->ipaddr);
    ipaddr_set_any(&netif->netmask);
    ipaddr_set_any(&netif->gateway);
    plat_memset(netif->name, 0, sizeof(netif->name));
    plat_strcpy(netif->name, name);
    plat_memset(&netif->hwaddr, 0, sizeof(netif->hwaddr));

    netif->type = NETIF_TYPE_NONE;
    netif->mtu = 0;
    nlist_node_init(&netif->node);

    net_err_t err = fixq_init(&netif->in_q, netif->in_q_buf, NETIF_INQ_SIZE, NLOCKER_THREAD);
    if (err < 0)
    {
        DBG_ERROR(DBG_NETIF_LEVEL, "init in fixq failed!");
        goto free_return;
        return NULL;
    }
    err = fixq_init(&netif->out_q, netif->out_q_buf, NETIF_OUTQ_SIZE, NLOCKER_THREAD);
    if (err < 0)
    {
        DBG_ERROR(DBG_NETIF_LEVEL, "init in fixq failed!");
        fixq_destroy(&netif->in_q);
        goto free_return;
        return NULL;
    }

    netif->ops = ops;
    netif->ops_data = ops_data;
    err = netif->ops->open(netif, netif->ops_data);
    if (err < 0)
    {
        DBG_ERROR(DBG_NETIF_LEVEL, "%s netif ops open failed!", netif->name);
        fixq_destroy(&netif->in_q);
        fixq_destroy(&netif->out_q);
        goto free_return;
    }

    netif->state = NETIF_OPENED;

    if (netif->type == NETIF_TYPE_NONE)
    {
        fixq_destroy(&netif->in_q);
        fixq_destroy(&netif->out_q);
        goto free_return;
    }

    netif->layer = netif_get_layer(netif->type);
    if (!netif->layer && netif->type != NETIF_TYPE_LOOP)
    {
        DBG_ERROR(DBG_NETIF_LEVEL, "get layer failed in netif:%s", netif->name);
        fixq_destroy(&netif->in_q);
        fixq_destroy(&netif->out_q);
        goto free_return;
    }

    nlist_insert_last(&netif_list, &netif->node);

    if (NETIF_TYPE_NONE == netif->type)
    {
        DBG_ERROR(DBG_NETIF_LEVEL, "netif type is error!");
    }

    return netif;

free_return:
    mblock_free(&netif_mblock, netif);
    if (netif->state == NETIF_OPENED)
    {
        netif->ops->close(netif);
    }
    return NULL;
}

/**
 * @brief 设置网络接口的各类ip地址
 * @param netif 网络接口
 * @param ip ip地址
 * @param mask 掩码地址
 * @param gateway 网关地址
 */
net_err_t netif_set_addr(netif_t *netif, ipaddr_t *ip, ipaddr_t *mask, ipaddr_t *gateway)
{
    ipaddr_copy(&netif->ipaddr, ip ? ip : ipaddr_get_any());
    ipaddr_copy(&netif->netmask, mask ? mask : ipaddr_get_any());
    ipaddr_copy(&netif->gateway, gateway ? gateway : ipaddr_get_any());
    return NET_ERR_OK;
}

/**
 * @brief 设置网络接口的硬件地址
 * @param netif 网络接口
 * @param hwaddr 传入的硬件地址
 * @param len 硬件地址长度
 */
net_err_t netif_set_hwaddr(netif_t *netif, const char *hwaddr, int len)
{
    plat_memcpy(netif->hwaddr.addr, hwaddr, len);
    netif->hwaddr.len = len;
    return NET_ERR_OK;
}

/**
 * @brief 激活网络接口
 */
net_err_t netif_set_active(netif_t *netif)
{
    if (!netif)
        return NET_ERR_PARAM;

    if (netif->state != NETIF_OPENED)
    {
        DBG_ERROR(DBG_NETIF_LEVEL, "netif:%s is not opened, can not activate!", netif->name);
        return NET_ERR_STATE;
    }

    netif->state = NETIF_ACTIVE;

    if (!netif_default && netif->type != NETIF_TYPE_LOOP)
    {
        netif_set_default(netif);
    }

    if (netif->layer)
    {
        net_err_t err = netif->layer->open(netif);
        if (err < NET_ERR_OK)
        {
            DBG_ERROR(DBG_NETIF_LEVEL, "layer open failed in netif:%s", netif->name);
            return NET_ERR_SYS;
        }
    }

    // 添加路由表
    ipaddr_t ip_net = ipaddr_get_net(&netif->ipaddr, &netif->netmask);
    ipaddr_t tmp_mask;
    ipaddr_from_str(&tmp_mask, "255.255.255.255");
    routetbl_add(&ip_net, &netif->netmask, ipaddr_get_any(), netif);
    routetbl_add(&netif->ipaddr, &tmp_mask, ipaddr_get_any(), netif);

    return NET_ERR_OK;
}

/**
 * @brief 关闭网络接口,并清空消息队列中的数据包
 */
net_err_t netif_set_deactive(netif_t *netif)
{
    if (!netif)
        return NET_ERR_PARAM;

    if (NETIF_ACTIVE != netif->state)
    {
        DBG_ERROR(DBG_NETIF_LEVEL, "netif:%s is not activated, can not be deactived!", netif->name);
        return NET_ERR_STATE;
    }

    // 关闭网络接口前,先清空接口中的消息队列
    pktbuf_t *buf;
    while ((buf = fixq_recv(&netif->in_q, DELIVER_NO_WAITTIME)) != NULL)
    {
        pktbuf_free(buf);
    }
    while ((buf = fixq_recv(&netif->out_q, DELIVER_NO_WAITTIME)) != NULL)
    {
        pktbuf_free(buf);
    }

    // 对默认使用的网络接口进行处理
    if (netif_default == netif)
    {
        netif_default = NULL;
        routetbl_remove(ipaddr_get_any(), ipaddr_get_any());
    }

    // 删除对应的路由表
    ipaddr_t ip_net = ipaddr_get_net(&netif->ipaddr, &netif->netmask);
    routetbl_remove(&ip_net, &netif->netmask);
    routetbl_remove(&netif->ipaddr, &netif->netmask);

    if (netif->layer)
    {
        net_err_t err = netif->layer->close(netif);
        if (err < NET_ERR_OK)
        {
            DBG_ERROR(DBG_NETIF_LEVEL, "layer close failed in netif:%s", netif->name);
            return NET_ERR_SYS;
        }
    }

    netif->state = NETIF_OPENED;
    return NET_ERR_OK;
}

/**
 * @brief 设置默认使用的网络接口
 */
net_err_t netif_set_default(netif_t *netif)
{
    if (netif_default)
    {
        // 设置前先删除对应的路由表项
        routetbl_remove(ipaddr_get_any(), ipaddr_get_any());
    }

    netif_default = netif;

    // 添加路由表
    if (!ipaddr_is_any(&netif->ipaddr))
    {
        routetbl_add(ipaddr_get_any(), ipaddr_get_any(), &netif->gateway, netif);
    }

    return NET_ERR_OK;
}

/**
 * @brief 获取默认网络接口
 */
netif_t *netif_get_default()
{
    return netif_default;
}

/**
 * @brief 关闭对应的网络接口
 */
net_err_t netif_close(netif_t *netif)
{
    if (!netif)
        return NET_ERR_PARAM;
    if (netif->state == NETIF_ACTIVE)
    {
        DBG_ERROR(DBG_NETIF_LEVEL, "the netif:%s is activated, can not close!", netif->name);
        return NET_ERR_STATE;
    }

    netif->ops->close(netif);
    netif->state = NETIF_CLOSED;

    // 从链表中进行删除
    nlist_remove(&netif_list, &netif->node);
    mblock_free(&netif_mblock, &netif);

    display_netif_list();
    return NET_ERR_OK;
}

/**
 * @brief 向in队列中塞入包
 */
net_err_t netif_put_in(netif_t *netif, pktbuf_t *buf, int tmo)
{
    if (!netif || !buf)
    {
        return NET_ERR_PARAM;
    }

    net_err_t err = fixq_send(&netif->in_q, buf, tmo);
    if (err < 0)
    {
        DBG_INFO(DBG_NETIF_LEVEL, "the in fixq in netif:%s is full!", netif->name);
        return NET_ERR_FULL;
    }

    // 别忘了通知核心工作线程
    exmsg_netif_in(netif);

    return NET_ERR_OK;
}

/**
 * @brief 从in队列中取包
 */
pktbuf_t *netif_get_in(netif_t *netif, int tmo)
{
    pktbuf_t *buf = fixq_recv(&netif->in_q, tmo);
    if (buf)
    {
        pktbuf_reset_acc(buf);
        return buf;
    }
    else
    {
        DBG_INFO(DBG_NETIF_LEVEL, "the netif:%s fixq is no message!", netif->name);
        return NULL;
    }
}

/**
 * @brief 向out队列中塞入包
 */
net_err_t netif_put_out(netif_t *netif, pktbuf_t *buf, int tmo)
{
    if (!netif || !buf)
    {
        return NET_ERR_PARAM;
    }

    net_err_t err = fixq_send(&netif->out_q, buf, tmo);
    if (err < 0)
    {
        DBG_INFO(DBG_NETIF_LEVEL, "the in fixq in netif:%s is full!", netif->name);
        return NET_ERR_FULL;
    }

    return NET_ERR_OK;
}

/**
 * @brief 从out队列中取包
 */
pktbuf_t *netif_get_out(netif_t *netif, int tmo)
{
    pktbuf_t *buf = fixq_recv(&netif->out_q, tmo);
    if (buf)
    {
        pktbuf_reset_acc(buf);
        return buf;
    }
    else
    {
        // DBG_INFO(DBG_NETIF_LEVEL, "the netif:%s fixq is no message!", netif->name);
        return NULL;
    }
}

/**
 * @brief 网络接口向外发送数据包
 * @param netif 网络接口
 * @param ipaddr 目的ip地址
 * @param buf 需要发送的包
 */
net_err_t netif_out(netif_t *netif, ipaddr_t *ipaddr, pktbuf_t *buf)
{
    net_err_t err = NET_ERR_OK;
    if (netif->layer)
    {
        netif->layer->out(netif, ipaddr, buf);
        // err = ether_raw_out(netif, NET_PROTOCOL_IPV4, ether_broadcast_addr(), buf);
    }
    else
    {
        err = netif_put_out(netif, buf, DELIVER_NO_WAITTIME);
    }

    if (err < 0)
    {
        DBG_INFO(DBG_NETIF_LEVEL, "netif:%s put pktbuf in outq failed!", netif->name);
        return NET_ERR_DELIVER;
    }

    return netif->ops->xmit(netif);
}

/**
 * @brief 注册链路层相关的函数指针
 * @param type 网络接口类型
 * @param layer 相关的函数指针变量
 */
net_err_t netif_register_layer(netif_type_t type, const link_layer_t *layer)
{
    if (type <= NETIF_TYPE_NONE || type >= NETIF_TYPE_SIZE)
    {
        DBG_ERROR(DBG_NETIF_LEVEL, "netif type:%d is error!", type);
        return NET_ERR_PARAM;
    }

    if (link_layers[type])
    {
        DBG_ERROR(DBG_NET_LEVEL, "the type:%d layer has been registered!", type);
        return NET_ERR_PARAM;
    }

    link_layers[type] = (link_layer_t *)layer;

    return NET_ERR_OK;
}